# _*_ coding:utf-8 _*_
# @Time  : 2022.12.13
# @Author: zizlee
import pathlib
import datetime
import json
import math
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from settings import FILE_STORAGE, STATIC_HOST

# Agg, is a non-interactive backend that can only write to files.
matplotlib.use('agg')  # 避免警告： UserWarning: Starting a Matplotlib GUI outside of the main thread will likely fail.
plt.rcParams['font.sans-serif'] = ['SimHei']  # 显示中文
plt.rcParams["axes.unicode_minus"] = False


# 有关平仓明细表的分析
class CloseStatistician(object):
    TEMP_FOLDER = pathlib.Path(FILE_STORAGE).joinpath('sysTemp/exDoctor')

    def __init__(self, close_data_list):
        self.close_df = pd.DataFrame(close_data_list)
        # print(self.close_df)

    # 多空盈亏分析饼图-表格
    def create_pupil_image_pie(self, filename_prefix, fig_size, xtick_count):
        pupil_table_data = self.pupil_profit()
        # count_labels = ['', '', '', '']  # '多单盈利', '多单亏损',  '空单亏损', '空单盈利',
        count_nums = [pupil_table_data['multiple_gain_count'], pupil_table_data['multiple_loss_count'],
                      pupil_table_data['empty_loss_count'], pupil_table_data['empty_gain_count']]
        amount_nums = [pupil_table_data['multiple_gain_money'], abs(pupil_table_data['multiple_loss_money']),
                       abs(pupil_table_data['empty_loss_money']), pupil_table_data['empty_gain_money']]

        # 多空盈亏次数饼图，去掉0的问题
        count_index = [i for i, n in enumerate(count_nums) if n != 0]
        count_nums = [c for i, c in enumerate(count_nums) if i in count_index]
        amount_index = [i for i, n in enumerate(amount_nums) if n != 0]
        amount_nums = [c for i, c in enumerate(amount_nums) if i in amount_index]
        # 设置labels
        radius = 0.6
        total_count = sum(count_nums)
        text = ['多单盈利', '多单亏损', '空单亏损', '空单盈利']
        count_pie_labels = [f'{text[i]}次数:{round(c / total_count * 100, 2)}%' for i, c in enumerate(count_nums)]
        fig, ax = plt.subplots(figsize=fig_size)
        pie_widget, texts = ax.pie(count_nums, shadow=False, textprops={'size': 'smaller'}, radius=radius)
        # 构造annotate函数的**kwargs参数，设置引导线线型
        kw = dict(arrowprops=dict(arrowstyle="-"), zorder=0, va="center")
        # 遍历饼块绘制注释标签和引导线
        for i, p in enumerate(pie_widget):
            # 根据matplotlib.patches.Wedge对象的theta1和theta2参数计算饼块均分点的角度
            ang = (p.theta2 - p.theta1) / 2.0 + p.theta1
            # 根据角度的弧度计算 饼块均分点的坐标（引导线的起点）
            y = np.sin(np.deg2rad(ang)) * radius
            x = np.cos(np.deg2rad(ang)) * radius
            # print(p.theta1, p.theta2, ang, np.deg2rad(ang), x, y)
            # 演示引导线起点位置
            # plt.plot(x, y, "or")
            # 根据x的值即角度所在象限确定引导线的对齐方式
            horizontalalignment = {-1: "right", 1: "left"}[int(np.sign(x))]
            # 设置引导线的连接方式
            connectionstyle = "angle,angleA=0,angleB={}".format(ang)
            kw["arrowprops"].update({"connectionstyle": connectionstyle})
            # 绘制注释标签和引导线
            plt.annotate(
                count_pie_labels[i],
                xy=(x, y),
                xytext=(1.01 * np.sign(x), 1.4 * y),
                horizontalalignment=horizontalalignment,
                **kw
            )
        plt.title('多空单盈亏次数占比')
        count_pie_file = self.TEMP_FOLDER.joinpath(f'{filename_prefix}_pupil_profit_count_pie.png')
        plt.savefig(count_pie_file)

        # 多空单盈亏金额占比
        total_amount = sum(amount_nums)
        amount_pie_label = [f'{text[i]}金额:{round(c / total_amount * 100, 2)}%' for i, c in enumerate(amount_nums)]
        flg, ax = plt.subplots(figsize=fig_size)
        pie_widget, texts = ax.pie(amount_nums, shadow=False, textprops={'size': 'smaller'}, radius=radius)
        kw = dict(arrowprops=dict(arrowstyle="-"), zorder=0, va="center")
        for i, p in enumerate(pie_widget):
            ang = (p.theta2 - p.theta1) / 2.0 + p.theta1
            y = np.sin(np.deg2rad(ang)) * radius
            x = np.cos(np.deg2rad(ang)) * radius
            horizontalalignment = {-1: "right", 1: "left"}[int(np.sign(x))]
            # 设置引导线的连接方式
            connectionstyle = "angle,angleA=0,angleB={}".format(ang)
            kw["arrowprops"].update({"connectionstyle": connectionstyle})
            # 绘制注释标签和引导线
            plt.annotate(
                amount_pie_label[i],
                xy=(x, y),
                xytext=(1.01 * np.sign(x), 1.4 * y),
                horizontalalignment=horizontalalignment,
                **kw
            )
        plt.title('多空单盈亏金额占比')
        fund_pie_file = self.TEMP_FOLDER.joinpath(f'{filename_prefix}_pupil_profit_amount_pie.png')
        plt.savefig(fund_pie_file)
        plt.close()
        # 将数据写入json文件
        json_file = self.TEMP_FOLDER.joinpath(f'{filename_prefix}_pupil_profit.json')
        with open(json_file, 'w', encoding='utf8') as f:
            json.dump(pupil_table_data, f, indent=2, ensure_ascii=False)

        img_count_file = str(count_pie_file).replace('\\', '/').replace(FILE_STORAGE, '')
        img_fund_file = str(fund_pie_file).replace('\\', '/').replace(FILE_STORAGE, '')
        return {
            'data': pupil_table_data,
            'img_count_pie':  img_count_file,
            'img_count_url': STATIC_HOST + img_count_file,
            'img_fund_pie': img_fund_file,
            'img_fund_url': STATIC_HOST + img_fund_file
        }

    # 品种盈亏分析,盈亏排名，单位利交比图-文字
    def create_variety_profit_image(self, filename_prefix, fig_size, xtick_count):
        variety_rank = self.variety_profit()
        unit_lj_rank = self.variety_unit_lj_ratio()
        # 生成品种盈亏排名柱形图
        x_labels = [v['variety_name'] for v in variety_rank['chart_data']]
        x_ticks = self.get_x_ticks(x_labels, xtick_count)
        fig, ax1 = plt.subplots(figsize=fig_size)
        plt.xticks([i for i in range(len(x_labels))], x_ticks, rotation=30, fontsize=9)
        ax1.bar(x_labels, [v['profit_close'] for v in variety_rank['chart_data']], zorder=10)
        ax1.set_xlabel('品种')
        ax1.set_ylabel('盈亏')
        plt.title('品种盈亏排名')
        for loc_axis in ['left', 'top', 'right']:
            ax1.spines[loc_axis].set_visible(False)
        plt.grid(axis='y', zorder=0)
        rank_img = self.TEMP_FOLDER.joinpath(f'{filename_prefix}_variety_profit_rank.png')
        plt.savefig(rank_img)

        rank_txt = self.TEMP_FOLDER.joinpath(f'{filename_prefix}_variety_profit_rank.txt')
        with open(rank_txt, 'w', encoding='utf8') as f:
            f.write(variety_rank['chart_description'])
        # 生成单位利交比排名柱形图
        x_labels = [v['variety_name'] for v in unit_lj_rank['lj_rate_data']]
        x_ticks = self.get_x_ticks(x_labels, xtick_count)

        fig, ax1 = plt.subplots(figsize=fig_size)
        plt.xticks([i for i in range(len(x_labels))], x_ticks, rotation=30, fontsize=9)
        ax1.bar(x_labels, [v['lj_rate'] for v in unit_lj_rank['lj_rate_data']], zorder=10)
        ax1.set_xlabel('品种')
        ax1.set_ylabel('单位利交比')
        plt.title('品种单位利交比排名')
        for loc_axis in ['left', 'top', 'right']:
            ax1.spines[loc_axis].set_visible(False)
        plt.grid(axis='y', zorder=0)
        lj_img = self.TEMP_FOLDER.joinpath(f'{filename_prefix}_variety_ljrate_rank.png')
        plt.savefig(lj_img)
        plt.close()
        lj_txt = self.TEMP_FOLDER.joinpath(f'{filename_prefix}_variety_ljrate_rank.txt')
        with open(lj_txt, 'w', encoding='utf8') as f:
            f.write(unit_lj_rank['lj_description'])

        rank_img = str(rank_img).replace('\\', '/').replace(FILE_STORAGE, '')
        lj_img = str(lj_img).replace('\\', '/').replace(FILE_STORAGE, '')
        return {
            'rank_img': rank_img,
            'rank_img_url': STATIC_HOST + rank_img,
            'rank_txt': variety_rank['chart_description'],
            'lj_img': lj_img,
            'lj_img_url': STATIC_HOST + lj_img,
            'lj_txt': unit_lj_rank['lj_description']
        }

    # 交易周期图，数据
    def create_exchange_period_image(self, filename_prefix, fig_size, xtick_count):
        exchange_period_data = self.exchange_period()
        type_list = [t['name'] for t in exchange_period_data['data']]
        type_value = [t['v'] for t in exchange_period_data['data']]
        explode = [0. for _ in range(1, len(type_list))]
        explode.insert(0, 0.1)

        fig, ax1 = plt.subplots(figsize=fig_size)
        ax1.pie(type_value, labels=type_list, shadow=True, autopct='%1.1f%%', explode=explode)
        ax1.axis('equal')
        plt.title('交易周期类型')
        img_file = self.TEMP_FOLDER.joinpath(f'{filename_prefix}_exchange_period_pie.png')
        plt.savefig(img_file)

        txt_file = self.TEMP_FOLDER.joinpath(f'{filename_prefix}_exchange_period_pie.txt')
        with open(txt_file, 'w', encoding='utf8') as f:
            f.write(exchange_period_data['description'])

        json_file = self.TEMP_FOLDER.joinpath(f'{filename_prefix}_exchange_period_pie.json')
        with open(json_file, 'w', encoding='utf8') as f:
            json.dump(exchange_period_data, f, indent=2, ensure_ascii=False)
        img_filename = str(img_file).replace('\\', '/').replace(FILE_STORAGE, '')
        return {
            'txt': exchange_period_data['description'],
            'data': exchange_period_data['data'],
            'img_file': img_filename,
            'img_url': STATIC_HOST + img_filename
        }

    # 平仓盈亏一览表
    def close_profit_overview(self, filename_prefix, doc=False):
        gain_df = self.close_df[self.close_df['profit_close'] > 0]
        loss_df = self.close_df[self.close_df['profit_close'] < 0]
        level_df = self.close_df[self.close_df['profit_close'] == 0]
        gain_count = gain_df.shape[0]  # 盈利交易次数
        loss_count = loss_df.shape[0]  # 亏损交易次数
        level_count = level_df.shape[0]  # 持平交易次数
        gain_amount = gain_df['profit_close'].sum().round(2)  # 盈利合计总额
        loss_amount = loss_df['profit_close'].sum().round(2)  # 亏损合计总额
        average_gain_amount = 0  #
        if gain_count > 0:
            average_gain_amount = round(gain_amount / gain_count, 2)  # 单笔平均盈利
        average_loss_amount = 0
        if loss_count > 0:
            average_loss_amount = round(loss_amount / loss_count, 2)  # 单笔平均亏损
        total_profit = round(gain_amount + loss_amount, 2)  # 总盈利
        total_count = gain_count + loss_count + level_count  # 总次数
        success_ratio_num = round(gain_count / total_count, 4)
        gain_divisor_loss = 1
        if average_loss_amount != 0:
            gain_divisor_loss = round(average_gain_amount / average_loss_amount, 4)
        if total_profit > 0:
            gain_divisor_loss = abs(gain_divisor_loss)  # 盈亏比
        result_data = {
            'overview': [
                {'name': '盈利单交易次数', 'key': 'gain_count', 'value': gain_count},
                {'name': '盈利单合计盈利', 'key': 'gain_amount', 'value': gain_amount},
                {'name': '盈利单平均盈利', 'key': 'average_gain_amount', 'value': average_gain_amount},
                {'name': '亏损单交易次数', 'key': 'loss_count', 'value': loss_count},
                {'name': '亏损单合计亏损', 'key': 'loss_amount', 'value': loss_amount},
                {'name': '亏损单平均亏损', 'key': 'average_loss_amount', 'value': average_loss_amount},
                {'name': '持平单交易次数', 'key': 'level_count', 'value': level_count},
                {'name': '持平单合计持平', 'key': 'level_amount', 'value': 0},
                {'name': '持平单平均持平', 'key': 'average_level_amount', 'value': 0},
                {'name': '总盈亏', 'key': 'total_profit', 'value': total_profit},
                {'name': '总次数', 'key': 'total_count', 'value': total_count},
                {'name': '胜率', 'key': 'success_ratio', 'value': success_ratio_num},
                {'name': '盈亏比', 'key': 'gain_divisor_loss', 'value': gain_divisor_loss},
            ],
            'row_count': self.close_df.shape[0],
        }
        if doc:
            with open(self.TEMP_FOLDER.joinpath(f'{filename_prefix}_close_profit_overview.json'), 'w', encoding='utf8') as f:
                json.dump(result_data, f, indent=2, ensure_ascii=False)
        return result_data

    # 多空盈亏分析
    def pupil_profit(self):
        close_df = self.close_df.copy()
        gain_df = close_df[close_df['profit_close'] > 0]
        loss_df = close_df[close_df['profit_close'] < 0]
        level_df = close_df[close_df['profit_close'] == 0]
        gain_count = gain_df.shape[0]  # 盈利交易次数
        loss_count = loss_df.shape[0]  # 亏损交易次数
        level_count = level_df.shape[0]  # 持平交易次数
        gain_amount = round(gain_df['profit_close'].sum(), 2)  # 盈利合计总额
        loss_amount = round(loss_df['profit_close'].sum(), 2)  # 亏损合计总额
        level_amount = 0  # 持平合计总额
        average_gain_amount = 0  #
        if gain_count > 0:
            average_gain_amount = round(gain_amount / gain_count, 2)  # 单笔平均盈利
        average_loss_amount = 0
        if loss_count > 0:
            average_loss_amount = round(loss_amount / loss_count, 2)  # 单笔平均亏损
        average_level_amount = 0  # 单笔平均持平
        total_profit = round(gain_amount + loss_amount, 2)  # 总盈利
        total_count = gain_count + loss_count + level_count  # 总次数
        success_ratio_num = round(gain_count / total_count, 4)
        success_ratio = '%.2f%%' % success_ratio_num * 100  # 胜率
        gain_divisor_loss = 0
        if average_loss_amount != 0:
            gain_divisor_loss = round(average_gain_amount / average_loss_amount, 4)
        if total_profit > 0:
            gain_divisor_loss = abs(gain_divisor_loss)  # 盈亏比

        # 多空盈亏分析
        buy_df = close_df[close_df['direction'] == '卖']  # 做多的单
        sale_df = close_df[close_df['direction'] == '买']  # 做空的单
        multiple_total_count = buy_df.shape[0]
        multiple_gain_count = buy_df[buy_df['profit_close'] > 0].shape[0]
        multiple_success_ratio = (multiple_gain_count / multiple_total_count) if multiple_total_count > 0 else 0

        empty_total_count = sale_df.shape[0]
        empty_gain_count = sale_df[sale_df['profit_close'] > 0].shape[0]
        empty_success_ratio = (empty_gain_count / empty_total_count) if empty_total_count > 0 else 0
        # 多单盈利每笔平均盈利
        multiple_gain_money = buy_df[buy_df['profit_close'] > 0]['profit_close'].sum()
        multiple_loss_money = buy_df[buy_df['profit_close'] < 0]['profit_close'].sum()
        multiple_average_gain = buy_df[buy_df['profit_close'] > 0]['profit_close'].mean()
        multiple_average_loss = buy_df[buy_df['profit_close'] < 0]['profit_close'].mean()
        multiple_gain_divisor_loss = (multiple_average_gain / multiple_average_loss) if multiple_average_loss != 0 else 0
        if abs(multiple_gain_money) > abs(multiple_loss_money):  # 做多盈利大于亏损
            multiple_gain_divisor_loss = abs(multiple_gain_divisor_loss)  # 多单盈亏比
        # 空单盈亏分析
        empty_gain_money = sale_df[sale_df['profit_close'] > 0]['profit_close'].sum()
        empty_loss_money = sale_df[sale_df['profit_close'] < 0]['profit_close'].sum()
        empty_average_gain = sale_df[sale_df['profit_close'] > 0]['profit_close'].mean()
        empty_average_loss = sale_df[sale_df['profit_close'] < 0]['profit_close'].mean()
        empty_gain_divisor_loss = (empty_average_gain / empty_average_loss) if empty_loss_money != 0 else 0
        if abs(empty_gain_money) > abs(empty_loss_money):
            empty_gain_divisor_loss = abs(empty_gain_divisor_loss)  # 空单盈亏比

        return {
            'multiple_gain_count': multiple_gain_count,  # 多单盈利次数
            'multiple_loss_count': buy_df[buy_df['profit_close'] < 0].shape[0],  # 多单亏损次数
            'multiple_level_count': buy_df[buy_df['profit_close'] == 0].shape[0],  # 多单持平次数
            'multiple_average_gain': round(multiple_average_gain, 2),
            'multiple_average_loss': round(multiple_average_loss, 2),  # 多单亏损每笔平均亏损
            'empty_gain_count': sale_df[sale_df['profit_close'] > 0].shape[0],  # 空单盈利次数
            'empty_loss_count': sale_df[sale_df['profit_close'] < 0].shape[0],  # 空单亏损次数
            'empty_level_count': sale_df[sale_df['profit_close'] == 0].shape[0],  # 空单持平次数
            'empty_average_gain': round(empty_average_gain, 2),  # 空单盈利每笔平均盈利
            'empty_average_loss': round(empty_average_loss, 2),  # 空单亏损每笔平均盈利
            'multiple_gain_money': round(multiple_gain_money, 2),  # 做多盈利金额
            'multiple_loss_money': round(multiple_loss_money, 2),  # 做多亏损金额
            'empty_gain_money': round(empty_gain_money, 2),  # 做空盈利金额
            'empty_loss_money': round(empty_loss_money, 2),  # 做空亏损金额
            'multiple_total_profit': buy_df['profit_close'].sum().round(2),  # 多单总盈利
            'empty_total_profit': sale_df['profit_close'].sum().round(2),  # 空单总盈利
            'multiple_total_count': multiple_total_count,  # 多单总次数
            'empty_total_count': empty_total_count,  # 空单总次数
            'multiple_success_ratio': multiple_success_ratio,  # 多单胜率
            'empty_success_ratio': empty_success_ratio,  # 空单胜率
            'multiple_gain_divisor_loss': round(multiple_gain_divisor_loss, 4),  # 多单盈亏比
            'empty_gain_divisor_loss': round(empty_gain_divisor_loss, 4)  # 空单盈亏比
        }

    # 品种盈亏分析
    def variety_profit(self):
        profit_df = self.close_df.groupby(by='variety_name', as_index=False)['profit_close'].sum().round(2)
        profit_df.sort_values(by='profit_close', ascending=False, inplace=True)
        variety_list = profit_df['variety_name'].tolist()
        gain_vdf = profit_df[profit_df['profit_close'] > 0].copy()

        loss_vdf = profit_df[profit_df['profit_close'] <= 0].copy()

        description = f"报告期内，交易涉及{'、'.join(variety_list[:10])}等{len(variety_list)}个品种。"
        if gain_vdf.empty:
            description += "其中没有盈利的品种。"
        else:
            gain_vdf.sort_values(by='profit_close', ascending=False, inplace=True)
            max_gain_variety = gain_vdf.head(1).to_dict(orient='records')[0]
            total_gain = gain_vdf['profit_close'].sum()
            if total_gain == 0:
                max_gain_rate = 1
            else:
                max_gain_rate = round(max_gain_variety['profit_close'] / total_gain, 4)
            description += f"其中盈利最高的品种为{max_gain_variety['variety_name']}，占总盈利的{round(max_gain_rate * 100, 2)}%。"
        if loss_vdf.empty:
            description += "没有亏损品种。"
        else:
            loss_vdf['profit_close'] = loss_vdf['profit_close'].apply(abs)
            loss_vdf.sort_values(by='profit_close', ascending=False, inplace=True)
            max_loss_variety = loss_vdf.head(1).to_dict(orient='records')[0]
            total_loss = loss_vdf['profit_close'].sum()
            if total_loss == 0:
                max_loss_rate = 1
            else:
                max_loss_rate = round(max_loss_variety['profit_close'] / total_loss, 4)
            description += f"亏损最大的品种为{max_loss_variety['variety_name']}，占总亏损的{round(max_loss_rate * 100, 2)}%。"

        # 文字解读
        return {
            'chart_data': profit_df.to_dict(orient='records'),
            'chart_description': description,
        }

    # 品种单位利交比
    def variety_unit_lj_ratio(self):
        # 盈亏的绝对值
        df = self.close_df.copy()
        df['profit_abs'] = df['profit_close'].apply(lambda x: abs(x))
        sum_df = df.groupby(by='variety_name', as_index=False)[['profit_abs', 'profit_close', 'amount_close']].sum()

        total_profit_base = sum_df['profit_abs'].sum()  # 总盈亏基数
        total_exchange_base = sum_df['amount_close'].sum()  # 总成交额
        # 计算单位利交比
        sum_df['yk_rate'] = (sum_df['profit_close'] / total_profit_base).round(4)  # 盈亏净额占比=品种净盈亏/总盈亏基数
        sum_df['cj_rate'] = (sum_df['amount_close'] / total_exchange_base).round(4)  # 成交额占比=品种成交额/总成交额
        sum_df['lj_rate'] = (sum_df['yk_rate'] / sum_df['cj_rate']).round(4)  # 单位利交比 = 品种盈亏净额占比 / 成交额占比

        sum_df.sort_values(by='profit_close', inplace=True)  # 按收益排序

        # 盈利前5
        gain_list = sum_df.tail(5).to_dict(orient='records')
        gain_list.reverse()
        rep_data = {
            'gain': list(filter(lambda x: x['profit_close'] > 0, gain_list)),
            'loss': list(filter(lambda x: x['profit_close'] <= 0, sum_df.head(5).to_dict(orient='records')))
        }

        sum_df.sort_values(by='lj_rate', inplace=True, ascending=False)  # 单位利交比倒序

        # 单位利交比前几
        if sum_df.shape[0] > 10:
            count = 5
        elif 6 < sum_df.shape[0] <= 10:
            count = 3
        else:
            count = 1
        lj_list = sum_df.head(count).to_dict(orient='records')
        rep_data['lj_first'] = lj_list
        lj_last = sum_df.tail(count).to_dict(orient='records')
        lj_last.reverse()
        rep_data['lj_last'] = lj_last
        rep_data['lj_rate_data'] = sum_df.to_dict(orient='records')

        first_variety_names = '、'.join([v['variety_name'] for v in rep_data['gain']])
        first_five_names = '、'.join([v['variety_name'] for v in rep_data['lj_first']])
        last_five_names = '、'.join([v['variety_name'] for v in rep_data['lj_last']])
        lj_description = f"报告期内，交易涉及{first_variety_names}等{len(rep_data['lj_rate_data'])}个品种，其中"
        lj_description += f"单位利交比前{count}品种为：{first_five_names}，倒数前{count}品种为：{last_five_names}。"
        rep_data['lj_description'] = lj_description
        return rep_data

    # 交易周期分析
    def exchange_period(self):
        df = self.close_df.copy()
        df['ex_date_o'] = df['ex_date'].apply(lambda x: datetime.datetime.strptime(str(x), '%Y%m%d'))
        df['date_open_o'] = df['date_open'].apply(lambda x: datetime.datetime.strptime(str(x), '%Y%m%d'))
        df['interval_o'] = df['ex_date_o'] - df['date_open_o']
        df['interval'] = df['interval_o'].apply(lambda x: x.days)
        # 总成交额
        zcj = df['amount_close'].sum().round(2) + df['amount_open'].sum().round(2)
        # 日内交易
        rn_df = df[df['interval'] < 1]
        rn_gain_count = 0
        # 1 日内交易成交额
        rn_cj = rn_df['amount_close'].sum().round(2)
        if rn_df.shape[0] == 0:  # 日内交易总次数为0
            rn_success_rate = '无记录'
        else:
            rn_gain_count = rn_df[rn_df['profit_close'] > 0].shape[0]  # 日内交易盈利次数
            rn_success_rate = f'{round(rn_gain_count / rn_df.shape[0] * 100, 2)}%'
        # 2 短线交易
        dx_df = df[(1 <= df['interval']) & (df['interval'] <= 5)]
        dx_gain_count = 0
        dx_cj = dx_df['amount_close'].sum().round(2)
        if dx_df.shape[0] == 0:  # 短线交易总次数为0
            dx_success_rate = '无记录'
        else:
            dx_gain_count = dx_df[dx_df['profit_close'] > 0].shape[0]  # 短线交易盈利次数
            dx_success_rate = f'{round(dx_gain_count / dx_df.shape[0] * 100, 2)}%'
        # 3 波段交易
        bd_df = df[(5 < df['interval']) & (df['interval'] <= 15)]
        bd_gain_count = 0
        bd_cj = bd_df['amount_close'].sum().round(2)
        if bd_df.shape[0] == 0:  # 波段交易次数为0
            bd_success_rate = '无记录'
        else:
            bd_gain_count = bd_df[bd_df['profit_close'] > 0].shape[0]  # 波动交易盈利次数
            bd_success_rate = f'{round(bd_gain_count / bd_df.shape[0] * 100, 2)}%'
        # 4 中长交易
        zc_df = df[df['interval'] > 15]
        zc_gain_count = 0
        zc_cj = zc_df['amount_close'].sum().round(2)
        if zc_df.shape[0] == 0:  # 中长线交易次数为0
            zc_success_rate = '无记录'
        else:
            zc_gain_count = zc_df[zc_df['profit_close'] > 0].shape[0]  # 中长线交易盈利次数
            zc_success_rate = f'{round(zc_gain_count / zc_df.shape[0] * 100, 2)}%'
        t_list = sorted([
            {'v': rn_cj, 'r': round(rn_cj * 2 / zcj, 4), 'tc': rn_df.shape[0], 'gc': rn_gain_count, 'success_rate': rn_success_rate, 't': 'rn', 'name': '日内'},
            {'v': dx_cj, 'r': round(dx_cj * 2 / zcj, 4), 'tc': dx_df.shape[0], 'gc': dx_gain_count, 'success_rate': dx_success_rate, 't': 'dx', 'name': '短线'},
            {'v': bd_cj, 'r': round(bd_cj * 2 / zcj, 4), 'tc': bd_df.shape[0], 'gc': bd_gain_count, 'success_rate': bd_success_rate, 't': 'bd', 'name': '波段'},
            {'v': zc_cj, 'r': round(zc_cj * 2 / zcj, 4), 'tc': zc_df.shape[0], 'gc': zc_gain_count, 'success_rate': zc_success_rate, 't': 'zc', 'name': '中长线'}
        ], key=lambda p: p['v'], reverse=True)
        # 文字说明
        description = f'在报告周期内，您的{t_list[0]["name"]}交易占比最大，为{round(t_list[0]["r"] * 100, 2)}%，'
        description += f'说明您交易中以{t_list[0]["name"]}交易为主，'
        description += f'其次为{t_list[1]["name"]}交易({round(t_list[1]["r"] * 100, 2)}%)。'
        return {
            'data': list(filter(lambda p: p['v'] != 0, t_list)),
            'description': description
        }

    @staticmethod
    def get_x_ticks(x_labels, xtick_count):
        gap_num = math.ceil(len(x_labels) / xtick_count)
        x_ticks = []
        for i, x in enumerate(x_labels):
            x_ticks.append(x) if i % gap_num == 0 else x_ticks.append('')
        x_ticks[-1] = x_labels[-1]
        return x_ticks
